﻿using System;
using Adaptive.Agrona;

namespace Unity.Type.BinaryType
{
    public static class MetadataHelper
    {
        public static string GetAsciiStringFromByteArray(byte[] buffer)
        {
            return System.Text.Encoding.ASCII.GetString(buffer);
        }

        public static int GetByteCount(string source)
        {
            return System.Text.Encoding.ASCII.GetByteCount(source);
        }

        public static byte[] GetByteArrayFromAsciiString(string buffer)
        {
            return System.Text.Encoding.ASCII.GetBytes(buffer);
        }

        public static string GetStringFromBytes(IMutableDirectBuffer buffer, int index, int length)
        {
            int count = buffer.Capacity - index;
            if (length > count)
            {
                MetadataExceptionHelper.ThrowIndexOutOfRangeException(buffer.Capacity);
            }
            byte[] data = new byte[length];
            buffer.GetBytes(index, data);
            return GetAsciiStringFromByteArray(data);
        }

        public static int SetBytesFromString(IMutableDirectBuffer buffer, string source, int index)
        {
            int available = buffer.Capacity - index;
            int byteCount = GetByteCount(source);

            if (byteCount > available)
            {
                MetadataExceptionHelper.ThrowIndexOutOfRangeException(buffer.Capacity);
            }

            byte[] data = GetByteArrayFromAsciiString(source);
            buffer.PutBytes(index, data, 0, data.Length);
            return byteCount;
        }

        public static string GetStringFromNullTerminatedBytes(IMutableDirectBuffer buffer, int index, int length, byte nullByte)
        {
            int count = Math.Min(length, buffer.Capacity - index);
            if (count <= 0)
            {
                MetadataExceptionHelper.ThrowIndexOutOfRangeException(index);
            }

            byte[] rawString = new byte[length];
            buffer.GetBytes(index, rawString, 0, length);

            int symbols = 0;
            int offset = 0;
            while (symbols < count && rawString[offset] != nullByte)
            {
                symbols++;
            }

            return System.Text.Encoding.ASCII.GetString(rawString, 0, symbols);
        }

        public static int SetNullTerminatedBytesFromString(IMutableDirectBuffer buffer, string source, int index, int limit, byte nullByte)
        {
            int available = Math.Min(limit, buffer.Capacity - index);
            if (available <= 0)
            {
                MetadataExceptionHelper.ThrowIndexOutOfRangeException(index);
            }
            byte[] rawBytes = new byte[limit];
            if (source == null)
            {
                rawBytes[0] = nullByte;
                buffer.PutBytes(index, rawBytes, 0, available);
                return 1;
            }

            int bytes = System.Text.Encoding.ASCII.GetByteCount(source);
            if (bytes > available)
            {
                MetadataExceptionHelper.ThrowIndexOutOfRangeException(available);
            }

            byte[] rawSource = System.Text.Encoding.ASCII.GetBytes(source);
            int offset = 0;
            while (offset < bytes)
            {
                rawBytes[offset] = rawSource[offset];
                offset++;
            }

            if (bytes < available)
            {
                offset++;
                rawBytes[offset] = nullByte;
            }

            buffer.PutBytes(index, rawBytes, 0, available);
            return bytes;
        }

    }

}

